package com.lccviolet;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author LiChaochao
 * @Date 2021/9/7 18:57
 * @Description ABADemo ABA问题的解决：时间戳原子引用
 */
public class ABADemo {

    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    static AtomicStampedReference<Integer> atomicStampedReference =
            new AtomicStampedReference<>(100, 1 );

    public static void main(String[] args) {
        // 演示ABA问题：即只关注开始和结尾的值没变，不在乎中间是否有变动
        new Thread(() -> {
            atomicReference.compareAndSet(100, 101);
            atomicReference.compareAndSet(101, 100);
        }, "t1").start();

        new Thread(() -> {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            atomicReference.compareAndSet(100, 200);
            System.out.println(atomicReference.get());
        }, "t2").start();

        try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("================================================================");

        // ABA问题的解决：对每次改动增加一个时间戳，不仅关注值，且关注改动次数
        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "第1次版本号：" + stamp);
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }

            atomicStampedReference.compareAndSet(100, 101,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "第2次版本号：" + atomicStampedReference.getStamp());

            atomicStampedReference.compareAndSet(101, 100,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "第3次版本号：" + atomicStampedReference.getStamp());
        }, "t3").start();

        new Thread(() -> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "第1次版本号：" + stamp);
            try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); }

            boolean result = atomicStampedReference.compareAndSet(100, 200,
                    stamp, atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "修改成功？：" + result +
                    "，当前最新版本：" + atomicStampedReference.getStamp() + "，当前最新值：" +
                    atomicStampedReference.getReference());
        }, "t4").start();

    }


}
